/**
 * 	write on 2005-10-26 23:58:46.
 */
package org.nanhill.xmlro.srojs;

import static org.nanhill.xmlro.srojs.JavascriptTag.BOOLEAN_FALSE;
import static org.nanhill.xmlro.srojs.JavascriptTag.BOOLEAN_TRUE;
import static org.nanhill.xmlro.srojs.JavascriptTag.COLON;
import static org.nanhill.xmlro.srojs.JavascriptTag.COMMA;
import static org.nanhill.xmlro.srojs.JavascriptTag.DATE_END;
import static org.nanhill.xmlro.srojs.JavascriptTag.DATE_START;
import static org.nanhill.xmlro.srojs.JavascriptTag.LIST_END;
import static org.nanhill.xmlro.srojs.JavascriptTag.LIST_START;
import static org.nanhill.xmlro.srojs.JavascriptTag.MAP_END;
import static org.nanhill.xmlro.srojs.JavascriptTag.MAP_START;
import static org.nanhill.xmlro.srojs.JavascriptTag.NULL;
import static org.nanhill.xmlro.srojs.JavascriptTag.STRING_END;
import static org.nanhill.xmlro.srojs.JavascriptTag.STRING_START;

import java.util.Date;

import org.nanhill.xmlro.AbstractXmlroOutput;
import org.nanhill.xmlro.Serializer;
import org.nanhill.xmlro.SerializerFactory;
import org.nanhill.xmlro.XmlroException;

/**
 * This class is not thread safe, use
 * <code>org.nanhill.xmlro.sro.SroAgent</code> only.
 * 
 * Sro java object serialize to javascript code parser.
 * 
 * @author alin
 * 
 */
public class JavascriptOutput extends AbstractXmlroOutput {
	private SerializerFactory serializerFactory;

	public void setSerializerFactory(SerializerFactory serializerFactory) {
		this.serializerFactory = serializerFactory;
	}

	// private static final char LN = '\n';

	public JavascriptOutput() {
		super();
	}

	public JavascriptOutput(StringBuilder builder) {
		super(builder);
	}

	public JavascriptOutput(Object obj, StringBuilder builder) {
		super(obj, builder);
	}

	public JavascriptOutput(Object obj) {
		super(obj);
	}

	public void construct() throws XmlroException {
		this.writeObject(this.getParsed());
	}

	/**
	 * Writes a double value to the stream. The double will be written only with
	 * the string value.
	 * 
	 * @param value
	 *            the double value to write.
	 */
	public void writeDouble(double value) {
		print(value);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.nanhill.protocol.gsp.io.GspOutput#writeBytes(byte[])
	 */
	public void writeBytes(byte[] v) {
		this.print(STRING_START);
		this.printBase64(v);
		this.print(STRING_END);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.nanhill.protocol.gsp.io.GspOutput#writeNull()
	 */
	public void writeNull() {
		this.print(NULL);
	}

	/**
	 * Writes a boolean value to the stream. The boolean will be written with
	 * the following syntax:
	 * 
	 * <code><pre>
	 *                                                                                                                                                                                                                                                                                                             &lt;boolean&gt;0&lt;/boolean&gt;
	 *                                                                                                                                                                                                                                                                                                             &lt;boolean&gt;1&lt;/boolean&gt;
	 * </pre></code>
	 * 
	 * @param value
	 *            the boolean value to write.
	 */
	public void writeBoolean(boolean value) {
		if (value)
			this.print(BOOLEAN_TRUE);
		else
			this.print(BOOLEAN_FALSE);
	}

	/**
	 * Writes the list header to the stream. List writers will call
	 * <code>writeListBegin</code> followed by the list contents and then call
	 * <code>writeListEnd</code>. Like following syntax:
	 * 
	 * <code>[ 1, &quot;alin&quot;]</code>
	 */
	public void writeListBegin() {
		print(LIST_START);
	}

	/**
	 * 
	 * @see org.nanhill.xmlro.XmlroOutput#writeListSize(int)
	 */
	public void writeListSize(int size) {
	}

	/**
	 * Writes the tail of the list to the stream.
	 */
	public void writeListEnd() {
		print(LIST_END);
	}

	/**
	 * Writes a string value to the stream using UTF-8 encoding. The string will
	 * be written with the following syntax:
	 * 
	 * <code>"alin"</code>
	 * 
	 * @param v
	 *            the string value to write.
	 */
	public void writeString(String v) {
		if (null == v) {
			this.writeNull();
		} else {
			print(STRING_START);
			this.print(v);
			print(STRING_END);
		}
	}

	/**
	 * Writes an integer value to the stream. The integer will be written with
	 * the string value.
	 * 
	 * @param value
	 *            the integer value to write.
	 */
	public void writeInt(int value) {
		print(value);
	}

	/**
	 * Writes a long value to the stream. The long will be written with the
	 * string value.
	 * 
	 * @param value
	 *            the long value to write.
	 */
	public void writeLong(long value) {
		print(value);
	}

	/**
	 * Writes the map header to the stream. Map writers will call
	 * <code>writeMapBegin</code> followed by the map contents and then call
	 * <code>writeMapEnd</code>. For example:
	 * 
	 * <code>
	 * { name:"alin", age:"24", married:false, email: "xalinx@gmail.com"}
	 * </code>
	 * 
	 */
	public void writeMapBegin() {
		print(MAP_START);
	}

	/**
	 * Writes the tail of the map to the stream.
	 */
	public void writeMapEnd() {
		print(MAP_END);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.nanhill.protocol.xmlro.Output#writeByte(byte)
	 */
	public void writeChar(char value) {
		this.print(value);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.nanhill.protocol.xmlro.Output#writeDate(java.util.Date)
	 */
	public void writeDate(Date date) {
		this.print(DATE_START);
		this.print(date.getTime());
		this.print(DATE_END);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.nanhill.protocol.xmlro.Output#writeShort(short)
	 */
	public void writeShort(short value) {
		this.writeInt(value);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.nanhill.protocol.xmlro.Output#writeByte(byte)
	 */
	public void writeByte(byte value) {
		this.writeInt(value);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.nanhill.protocol.xmlro.Output#writeFloat(float)
	 */
	public void writeFloat(float v) {
		this.writeDouble(v);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.nanhill.xmlro.XmlroOutput#writeMapElementSplit()
	 */
	public void writeMapElementSplit() {
		this.print(COMMA);
	}

	public void writeMapKey(String key) {
		this.print(key);
		this.print(COLON);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.nanhill.xmlro.XmlroOutput#writeListElementSplit()
	 */
	public void writeListElementSplit() {
		this.print(COMMA);
		// this.print(LN);
	}

	@Override
	protected Serializer getSerializer(Class clz) {
		return this.serializerFactory.getSerializer(clz);
	}

	public void writeFooter() {
	}

	public void writeHeader() {
	}

}
